package com.example.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;

/**
 * JWT工具类
 */
public class JwtTokenUtil {
    // 定义token返回头部
    public static final String AUTH_HEADER_KEY = "Authorization";

    // token前缀
    public static final String TOKEN_PREFIX = "Bearer-";

    // 签名密钥
    public static final String KEY = "q3t6w9z$C&F)J@NcQfTjWnZr4u7x";

    // 有效期默认为2h
    public static final Long EXPIRATION_TIME = 1000L * 60 * 60 * 2;

    /**
     * 创建token
     *
     * @param content 用户信息（负载）
     * @return token
     */
    public static String createToken(String content) {
        // 创建builder对象
        JWTCreator.Builder builder = JWT.create();
        String sign = builder
                .withSubject(content)
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .sign(Algorithm.HMAC512(KEY));
        return TOKEN_PREFIX + sign;

        /* 设置用户信息不是withClaim，为什么是withSubject？
        withSubject 的作用：withSubject是JWT标准字段，专门用于设置token的主题，
            通常用于存储简单、核心的信息，如用户ID、用户名等
            标准字段：.withSubject()、.withIssuer()、.withExpiresAt()等
        withClaim 的作用：withClaim 用于添加自定义声明（自定义字段）
            可以添加任意数量的自定义属性，适合存储复杂或特定的用户信息

        看个示例：
            .withSubject("user")  // 标准字段，表明是哪个用户
            .withClaim("userId", 12345L)  // 自定义字段
            .withClaim("role", "admin")
            .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
        结果：
            {
                "sub": "user",
                "userId": 12345,
                "role": "admin",
                "exp": 1732106400
            }
        解析：
            jwt.getSubject(); // user
            jwt.getClaim("userId").asLong(); // 12345
            jwt.getClaim("role").asString(); // admin
         */
    }


    /**
     * 验证token
     *
     * @param token token
     * @return 用户信息
     */
    public static String verifyToken(String token) throws Exception {
        try {
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC512(KEY)).build();
            DecodedJWT verify = jwtVerifier.verify(token.replace(TOKEN_PREFIX, ""));
            return verify.getSubject();
        } catch (TokenExpiredException e) {
            throw new Exception("token已失效，请重新登录", e);
        } catch (JWTVerificationException e) {
            throw new Exception("token验证失败!", e);
        }
    }
}
